package com.growthsee.framework.security.filter;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.growthsee.common.core.domain.AjaxResult;
import com.growthsee.common.core.domain.model.LoginUser;
import com.growthsee.framework.config.wechat.WechatMpProperties;
import com.growthsee.framework.config.wechat.WxMpOAuth2AccessToken;
import com.growthsee.framework.config.wechat.WxMpUser;
import com.growthsee.framework.security.token.WeixinAuthenticationToken;
import com.growthsee.framework.web.service.UserDetailsServiceImpl;
import com.growthsee.rider.utils.OkhttpUtil;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

public class WeixinAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    private String usernameParameter = "code";
    private String passwordParameter = "state";
    private boolean postOnly = true;
    private WechatMpProperties properties;
    private UserDetailsServiceImpl userService;


    public WeixinAuthenticationFilter() {
        super(new AntPathRequestMatcher("/wx/login", "GET"));
    }

    /**
     * 重写 该方法，判断是否包含 code ,没有：重定向到微信服务器，获取code ,有：则判断 state 值 ， 接着获取UniId ,对比数据库不存在就更新。
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (this.postOnly && !request.getMethod().equals("POST") && !request.getMethod().equals("GET")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }else {
            String username = this.obtainUsername(request);
            String password = this.obtainPassword(request);

            WxMpOAuth2AccessToken oAuth2AccessToken = null;
            try {
                String url = String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", properties.getAppId(), properties.getSecret(), username);
                String accessToken = OkhttpUtil.doGetHttpRequest(url);
                oAuth2AccessToken  = JSONArray.parseObject(accessToken, WxMpOAuth2AccessToken.class);
                if (oAuth2AccessToken == null || StringUtils.isEmpty(oAuth2AccessToken.getAccessToken())) {
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().write(JSONUtil.toJsonStr(AjaxResult.error("微信登录失败", -1)));
                    return null;
                }
                String openId =oAuth2AccessToken.getOpenId();
                LoginUser userDetails = userService.loadUserByOpenId(openId);
                if (Objects.isNull(userDetails.getUser())) {
                    String userUrl = String.format("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN", oAuth2AccessToken.getAccessToken(), properties.getAppId());
                    String user = OkhttpUtil.doGetHttpRequest(userUrl);
                    WxMpUser wxMpUser = JSONArray.parseObject(user, WxMpUser.class);
                    if(wxMpUser!=null){
                        userService.saveWxMpUser(wxMpUser);
                    }
                }
                WeixinAuthenticationToken authRequest = new WeixinAuthenticationToken(openId, password);
                this.setDetails(request, authRequest);
                Authentication authenticate = this.getAuthenticationManager().authenticate(authRequest);
                return authenticate;
            }catch (Exception e){
                e.printStackTrace();
            }
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(JSONUtil.toJsonStr(AjaxResult.error("微信登录失败", -1)));
            return null;
        }
    }

    @Nullable
    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(this.passwordParameter);
    }

    @Nullable
    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(this.usernameParameter);
    }

    protected void setDetails(HttpServletRequest request, WeixinAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }

    public void setUsernameParameter(String usernameParameter) {
        Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
        this.usernameParameter = usernameParameter;
    }

    public void setPasswordParameter(String passwordParameter) {
        Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
        this.passwordParameter = passwordParameter;
    }

    public void setPostOnly(boolean postOnly) {
        this.postOnly = postOnly;
    }

    public final String getUsernameParameter() {
        return this.usernameParameter;
    }

    public final String getPasswordParameter() {
        return this.passwordParameter;
    }


    public void setProperties(WechatMpProperties properties) {
        this.properties = properties;
    }
    public void setUserService(UserDetailsServiceImpl userService) {
        this.userService = userService;
    }
}
